// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: fengyang

#pragma once

#include <memory>
#include <string>

#include <glog/logging.h>

#include "coin2/exchange/base/executor/live_executor.h"
#include "coin2/exchange/base/feed/ws/feed_subscription_spec.h"
#include "coin2/exchange/base/market/market_exchange_api.h"
#include "quickfix/Application.h"
#include "quickfix/Initiator.h"
#include "quickfix/MessageStore.h"
#include "quickfix/SSLSocketInitiator.h"
#include "quickfix/SessionSettings.h"
#include "quickfix/SocketInitiator.h"

namespace coin2::exchange::base::feed {
namespace impl {

class FixConnection : public FIX::Application {
 public:
  FixConnection() {}

  virtual std::shared_ptr<FIX::SessionSettings> GetSessionSettings() = 0;
  virtual void Start() {
    settings_ = this->GetSessionSettings();
    store_factory_ = std::make_unique<FIX::MemoryStoreFactory>();
    bool use_non_ssl = false;
    if (settings_->get().has("UseNonSSL") && settings_->get().getBool("UseNonSSL")) {
      use_non_ssl = true;
    }

    LOG(INFO) << "Initiating " << (use_non_ssl ? "Non-SSL" : "SSL") << " feed connection";

    if (!use_non_ssl) {
      initiator_ = std::make_unique<FIX::SSLSocketInitiator>(*this, *store_factory_, *settings_);
    } else {
      initiator_ = std::make_unique<FIX::SocketInitiator>(*this, *store_factory_, *settings_);
    }

    initiator_->start();
  }

  virtual void Stop() {
    settings_.reset();
    store_factory_.reset();
    initiator_->stop();
    initiator_.reset();
  }

  static std::shared_ptr<FixConnection> NewFixConnection(
      executor::LiveAsyncExecutor* exec,
      const WsConnectionConfig& config);

 private:
  std::shared_ptr<FIX::SessionSettings> settings_;
  std::shared_ptr<FIX::MemoryStoreFactory> store_factory_;
  std::shared_ptr<FIX::Initiator> initiator_;
};

}  // namespace impl

using impl::FixConnection;
}  // namespace coin2::exchange::base::feed
